package cn.lyf.currey;

import java.util.function.Function;

// Either 函子
public abstract class Either<V, E> {
    // 转元组
    public Tuple.Tuple2<V, E> tupled() {
        return Tuple.of(_1, _2);
    }

    // 获取结果
    public V getVal() {
        return _1;
    }

    // 获取错误信息
    public E getErr() {
        return _2;
    }

    private V _1;
    private E _2;

    private Either(V v, E e) {
        _1 = v;
        _2 = e;
    }

    // 正常流程返回
    public static class Left<V, E> extends Either<V, E> {

        private Left(V v) {
            super(v, null);
        }

        @Override
        public <R> Either<R, E> map(Function<? super V, Either<R, E>> fx) {
            return fx.apply(super._1);
        }
        @Override
        public String toString() {
            return "Left(" + super._1 + ")";
        }
    }

    // 发生错误时返回
    public static class Right<V, E> extends Either<V, E> {
        private Right(E e) {
            super(null, e);
        }

        @Override
        @SuppressWarnings("unchecked")
        public <R> Either<R, E> map(Function<? super V, Either<R, E>> fx) {
            return (Either<R, E>) this;
        }
        @Override
        public String toString() {
            return "Right("+super._2+")";
        }
    }

    abstract public <R> Either<R, E> map(Function<? super V, Either<R, E>> fx);

    public static <R, E> Either<R, E> right(E msg) {
        return new Right<R, E>(msg);
    }

    public static <R, E> Either<R, E> left(R val) {
        return new Left<R, E>(val);
    }

    public static <V, E> Either<V, E> of(V val) {
        return left(val);
    }

    public static <V, E> Either<V, E> of(V val, Class<E> clazz) {
        return left(val);
    }

    @SuppressWarnings("unchecked")
    // 捕获Exception包装
    public static <V, R> Function<V, Either<R, Exception>> catchWrapper(Function<? super V, ? extends R> fx) {
        return v -> {
            try {
                return left(((Function<V, R>) fx).apply(v));
            } catch (Exception e) {
                return right(e);
            }
        };
    }

    @SuppressWarnings("unchecked")
    @SafeVarargs
    // 多个捕获
    // 通过返回值推导，返回值不要用通配符
    final public static <V, R> Function<V, Either<R,Exception>> catchWrapper(Function<? super V,? extends R> fx,
            Class<? extends Exception>... captureList) {
        return v -> {
            try {
                return left(((Function<V, R>) fx).apply(v));
            } catch (Exception e) {
                for (int i = 0; i < captureList.length; i++) {
                    if (captureList[i].isInstance(e)) {
                        return right(e);
                    }
                }
                throw e;
            }
        };
    }

}
